package com.puny.utils
{
	import com.puny.mvc.MvcEvent;
	import com.puny.mvc.models.Model;
	
	import flash.display.Sprite;
	import flash.events.Event;
	
	import flexunit.framework.TestCase;

	public class PetriNetTest extends TestCase
	{
		public function PetriNetTest(methodName:String=null)
		{
			super(methodName);
		}
		
		public function testLoadFile():void {
			var net:PetriNet = new PetriNet("petrinet.xml");
			net.addEventListener(MvcEvent.READY, addAsync(readyHandler,1000));
		}
		
		private function readyHandler(event:Event):void {
			var net:PetriNet = event.currentTarget as PetriNet;
			net.removeEventListener(MvcEvent.READY, readyHandler);
			assertEquals(5,net.places.length);
			assertEquals(5,net.transitions.length);
			
			assertEquals("place0:place1", net.currentState);
			assertTrue(net.canFire("tran0"));
			assertFalse(net.canFire("tran1"));
			assertFalse(net.canFire("tran2"));
			assertFalse(net.canFire("tran3"));
			assertFalse(net.canFire("tran4"));
			assertEquals("",net.transit("tran1"));
			assertEquals("",net.transit("tran2"));
			assertEquals("",net.transit("tran3"));
			assertEquals("",net.transit("tran4"));
			
			var transition:Model = net.takeTokenFromPlace("tran0"); 
			assertEquals("", net.currentState);
			assertEquals("tran0",transition.id);
			assertEquals(1,transition.token);
			assertEquals(0,net.places[0].token);
			assertEquals(0,net.places[1].token);
			assertFalse(net.canFire("tran0"));
			assertFalse(net.canFire("tran1"));
			assertFalse(net.canFire("tran2"));
			assertFalse(net.canFire("tran3"));
			assertFalse(net.canFire("tran4"));
			
			assertEquals("place2:place3",net.pushTokenToPlace("tran0"));
			assertEquals(0,transition.token);
			assertEquals(1,net.places[2].token);
			assertEquals(1,net.places[3].token);
			assertEquals("place2:place3", net.currentState);
			
			assertFalse(net.canFire("tran0"));
			assertTrue(net.canFire("tran1"));
			assertTrue(net.canFire("tran2"));
			assertTrue(net.canFire("tran3"));
			assertFalse(net.canFire("tran4"));
			
			assertEquals("",net.pushTokenToPlace("tran0"));
			assertEquals("",net.pushTokenToPlace("nonexist_transition"));
			
			assertEquals("",net.transit("nonexist_transition"));
			assertEquals("",net.transit("tran4"));
			assertEquals("place2:place4",net.transit("tran3"));
			
			assertFalse(net.canFire("nonexist_transtion"));
			assertEquals("place2:place4", net.currentState);
			
			net.initialize();
			assertEquals("place0:place1",net.currentState);
		}
		
		public function testEmbeddedPetriNet():void {
			var configure:String = "<?xml version='1.0' encoding='utf-8'?>";
			configure += "<configure>";
			configure += "  <network focus='on'>";
			configure += "    <place id='place0' token='1'/>";
			configure += "    <transition id='tran0' name='my transition' from='place0'/>";
			configure += "    <place id='place1' name='my place' from='tran0'/>";
			configure += "  </network>";
			configure += "  <network focus='off'>";
			configure += "    <place id='place2' token='1'/>";
			configure += "  </network>";
			configure += "  <network>";
			configure += "    <place id='place3' token='1'/>";
			configure += "  </network>";
			configure += "</configure>";
			var net:PetriNet = new PetriNet(new XML(configure));
			assertEquals(4,net.places.length);
			assertTrue(net.canFire("tran0"));
			assertEquals("my place",net.transit("tran0"));
		}
		
		public function testEndWithTransition():void {
			var configure:String = "<?xml version='1.0' encoding='utf-8'?>";
			configure += "<configure>";
			configure += "  <network focus='on'>";
			configure += "    <place id='place0' token='1'/>";
			configure += "    <transition id='tran0' name='my transition' from='place0'/>";
			configure += "    <place id='place1' name='my place' from='tran0'/>";
			configure += "    <transition id='tran1' name='finish' from='place1'/>";
			configure += "  </network>";
			configure += "  <network focus='off'>";
			configure += "    <place id='place2' token='1'/>";
			configure += "  </network>";
			configure += "  <network>";
			configure += "    <place id='place3' token='1'/>";
			configure += "  </network>";
			configure += "</configure>";
			var net:PetriNet = new PetriNet(new XML(configure));
			assertEquals("",net.transit("tran1"));
			assertEquals("my place",net.transit("tran0"));
			assertEquals("",net.transit("tran1"));
		}
		
		public function testErrorConfiguration():void {
			var error:Boolean = false;
			var configure:String = "<?xml version='1.0' encoding='utf-8'?>";
			configure += "<configure>";
			configure += "  <network focus='on'>";
			configure += "    <place id='place0' token='1'/>";
			configure += "    <transition id='tran0' name='my transition' from='place0'/>";
			configure += "    <place id='place1' name='my place' from='tran5'/>";
			configure += "    <transition id='tran1' name='finish' from='place1'/>";
			configure += "  </network>";
			configure += "</configure>";
			try {
				var net:PetriNet = new PetriNet(new XML(configure));
			} catch (e:Error) {
				assertTrue(e is ReferenceError);
				error = true;
			}
			assertTrue(error);
		}
		
		public function testWrongObject():void {
			var error:Boolean = false;
			try {
				var net:PetriNet = new PetriNet(new Sprite());
			} catch(e:Error) {
				assertTrue(e is ArgumentError);
				error = true;				
			}
			assertTrue(error);
		}
	}
}